
// Copyright (c) 2012, 2013 All Right Reserved, http://hpc.utp.edu.my
// Author: Nordin Zakaria nordinzakaria@gmail.com
// All rights reserved.


#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
#include <assert.h>
#include "Random.h"

#ifndef ADJMATRIX_CLASS
#define ADJMATRIX_CLASS

#define COMM_MEAN 195
#define COMM_SDV 40

//! Adjacency matrix that stores inter-agent communication weights
/*!
    Each weight is stored as 'unsigned char', hence the value ranges from 0 to 255.
*/
class AdjMatrix
	{
	private:
	//! 2-dimensional pointer that points to the adjacency matrix
	unsigned char **matrix;	
	//! The dimension of the matrix
	unsigned int N;

	public:

	//! Blank constructor
	AdjMatrix() {
		matrix = NULL;
		N = 0;
		}

	//! Destructor - deallocate the 2-dimensional array if it has been allocated
	~AdjMatrix() {
		clear();
		}

	//! get the matrix dimension
	unsigned int getN() const {
		return N;
		}

	//! get the matrix pointer
	unsigned char** get() {
		return matrix;
		}

	//! deallocate the 2-dimensional array if it has been allocated
	void clear();

	//! set the matrix to 0s.
	void zeros();

	//! initialize the matrix
	/*!
	    The 2-dimensional array representing the matrix will be allocated.
	    \param N   the matrix dimension
	*/
	void init(unsigned int N);

	//! set a value in the matrix
	/*!
	    Note that the value must be an unsigned char - hence the value ranges from 0 to 255.
	    \param i   the i index
	    \param j   the j index
	    \param val  the value to be assigned at index (i,j)
	*/
	void set(int i, int j, unsigned char val) {
		matrix[j][i] = val;
		}

	//! get a value from the matrix
	/*!
	    Get the value from the matrix at index (i,j)
	    \param i   the i index
	    \param j   the j index
	    \return  the value 
	*/
	unsigned char get(int i, int j) const {
		return matrix[j][i];
		}

	//! randomize the matrix
	void rand();

	//! matrix assignment
	AdjMatrix& operator=(const AdjMatrix& obj);

	//! Add another matrix to this matrix
	/*!
	    the other matrix must be of the same dimension
	    \param obj   the other matrix
	*/
	AdjMatrix& operator+=(const AdjMatrix& obj);

	//! extract from the matrix a submatrix that covers a set of indices
	/*!
	    \param workers   the list of indices
	    \param submat   the extracted submatrix
	*/
	void extract(const vector<unsigned int> &workers, AdjMatrix& submat);

	//! add to the matrix a submatrix that covers a set of indices
	/*!
	    \param workers   the list of indices
	    \param submat   the submatrix
	*/
	void add(const vector<unsigned int> &workers, const AdjMatrix& submat);

	//! read matrix values from a text file
	/*!
	    \param intext   the input file
	*/
	void fromText(string intext);

	//! write matrix values to a file
	/*!
	    \param outtext   the output file
	*/
	void toText(string outtext);

	//! read matrix values from a binary file
	/*!
	    \param infile   the input file
	*/
	void read(FILE *infile);

	//! write matrix values to a binary file
	/*!
	    \param outfile   the output file
	*/
	void write(FILE *outfile);

	//! write matrix values to a binary file
	friend ostream& operator<<(ostream& os, const AdjMatrix& obj);

	//! read matrix values from a binary file
	friend istream& operator>>(istream& is, AdjMatrix& job);

	};

#endif

